home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Applications / Eudora 1.3.1 / source / comp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-16  |  15.3 KB  |  614 lines  |  [TEXT/MPS ]

  1. #define FILE_NUM 7
  2. /* Copyright (c) 1990-1992 by the University of Illinois Board of Trustees */
  3. #pragma load EUDORA_LOAD
  4. #pragma segment Outgoing
  5.  
  6. /************************************************************************
  7.  * private function declarations
  8.  ************************************************************************/
  9. TEHandle GetCompTexts(MessType **messH);
  10. void MakeCompTitle(UPtr string, TOCType **tocH, int sumNum);
  11. int WriteComp(MessType **messH, short refN, long offset);
  12. int WriteCompHeader(short refN,MessType **messH,int which);
  13. void SuckHeaderText(UPtr string,int size,TEHandle teh); 
  14. void CompBecameVisible(MyWindowPtr win);
  15.  
  16. /**********************************************************************
  17.  * OpenComp - open an outgoing message
  18.  **********************************************************************/
  19. MyWindowPtr OpenComp(TOCType **tocH, int sumNum, MyWindowPtr win, Boolean showIt)
  20. {
  21.     Str255 title;
  22.     MessType **messH;
  23.     ControlHandle grumble;
  24.     
  25.     CycleBalls();
  26.     if ((messH = (MessType **)NewZHandle(sizeof(MessType)))==nil)
  27.         return(nil);
  28.         
  29.     win = GetNewMyWindow(MESSAGE_WIND,win,InFront,False,True);
  30.     if (!win)
  31.     {
  32.         DisposHandle(messH);
  33.         return(nil);
  34.     }
  35.     ((WindowPeek)win)->windowKind = COMP_WIN;
  36.     
  37.     SetPort(win);
  38.     
  39.     (*tocH)->sums[sumNum].messH = messH;
  40.     MakeCompTitle(title,tocH,sumNum);
  41.     
  42.     (*messH)->win = win;
  43.     (*messH)->sumNum = sumNum;
  44.     (*messH)->tocH = tocH;
  45.     
  46.     ((WindowPeek)win)->refCon = (long)messH;
  47.     win->close = CompClose;
  48.     win->scroll = CompScroll;
  49.     win->didResize = CompDidResize;
  50.     win->click = CompClick;
  51.     win->menu = CompMenu;
  52.     win->key = CompKey;
  53.     win->button = CompButton;
  54.     win->vPitch = FontLead;
  55.     win->hPitch = FontWidth;
  56.     win->position = MessagePosition;
  57.     win->help = CompHelp;
  58.     win->gonnaShow = CompBecameVisible;
  59.     win->textChanged = CompHasChanged;
  60.     win->zoomSize = CompZoomSize;
  61.  
  62.     LL_Push(MessList,messH);
  63.     
  64.     if (PrefIsSet(PREF_ICON_BAR))
  65.     {
  66.         (*tocH)->sums[sumNum].flags |= FLAG_ICON_BAR;
  67.         win->topMargin = GetRLong(COMP_TOP_MARGIN);
  68.         grumble = GetNewControl(SEND_NOW_CNTL,win);
  69.         (*messH)->sendButton = grumble;
  70.         SetGreyControl((*messH)->sendButton,(*tocH)->sums[sumNum].state==SENT);
  71.     }
  72.     else
  73.         (*tocH)->sums[sumNum].flags &= ~FLAG_ICON_BAR;
  74.  
  75.     if (GetCompTexts(messH)==nil)
  76.     {
  77.         CloseMyWindow(win);
  78.         return(nil);
  79.     }
  80.     
  81.     TextFont(0);
  82.     TextSize(0);
  83.     win->update = CompUpdate;
  84.     if (showIt)
  85.         ShowMyWindow(win);
  86.     InvalContent(win);
  87.     SetWTitle(win,title);
  88.     AttachSelect((*messH)->txes[ATTACH_HEAD-1]);
  89.     
  90.     UpdateMyWindow(win);
  91.     
  92.     return(win);
  93. }
  94.  
  95. /************************************************************************
  96.  * CompBecameVisible - select an appropriate field
  97.  ************************************************************************/
  98. void CompBecameVisible(MyWindowPtr win)
  99. {
  100.     MessHandle messH = Win2MessH(win);
  101.     
  102.     if (!(*(*messH)->txes[TO_HEAD-1])->teLength)
  103.         CompActivateField(messH,TO_HEAD-1);
  104.     else if (!(*(*messH)->txes[SUBJ_HEAD-1])->teLength) 
  105.         CompActivateField(messH,SUBJ_HEAD-1);
  106.     else
  107.         CompActivateField(messH,HEAD_LIMIT-1);
  108.     if ((*win->vBar)->contrlMax)
  109.         ScrollIt(win,0,INFINITY);
  110.     else
  111.         HiliteControl(win->vBar,0);
  112. }
  113.  
  114. /**********************************************************************
  115.  * CountCompLines - count the number of lines in a message under
  116.  * composition.
  117.  **********************************************************************/
  118. int CountCompLines(MessType **messH)
  119. {
  120.     int lines = 0;
  121.     int h=0;
  122.     
  123.     for (h=0;h<HEAD_LIMIT;h++)
  124.         if ((*messH)->txes[h] && CountTeLines((*messH)->txes[h]))
  125.             lines += CountTeLines((*messH)->txes[h]);
  126.         else
  127.             lines++;
  128.     
  129.     return(lines);
  130. }
  131.  
  132. /**********************************************************************
  133.  * GetCompTexts - get the fields of an under-composition message
  134.  * First, we read ALL the message into a buffer.    Then, we grab the
  135.  * header items, stuff them one by one into appropriate TERec's.  After
  136.  * the headers are safely tucked away, we move the body to the
  137.  * beginning of the buffer, and make a TERec out of that.
  138.  * This routine assumes that the out box has been created in a very
  139.  * particular format; to wit:
  140.  *        Sendmail-style from line
  141.  *        To:
  142.  *        From:
  143.  *        Subject:
  144.  *        Cc:
  145.  *        Date:
  146.  *        <blank line>
  147.  *        body of message
  148.  * The header items must NOT contain newlines, and MUST be presented in
  149.  * the proper order.
  150.  **********************************************************************/
  151. TEHandle GetCompTexts(MessType **messH)
  152. {
  153.     MyWindowPtr win = (*messH)->win;
  154.     int sumNum = (*messH)->sumNum;
  155.     TOCType **tocH = (*messH)->tocH;
  156.     UHandle buffer = nil;
  157.     int which, err;
  158.     Rect template;
  159.     char *cp, *ep;
  160.     TEHandle teh;
  161.     
  162.     /*
  163.      * allocate space for the text
  164.      */
  165.     if ((buffer=NuHandle((*tocH)->sums[sumNum].length+1))==nil)
  166.     {
  167.         WarnUser(NO_MESS_BUF,MemError());
  168.         return(nil);
  169.     }
  170.     
  171.     /*
  172.      * read it
  173.      */
  174.     LDRef(buffer);
  175.     if (err=ReadMessage(tocH,sumNum,*buffer))
  176.         goto failure;
  177.     UL(buffer);
  178.     
  179.     /*
  180.      * now, set up the TERec's
  181.      */
  182.     template = win->contR;            /* some size; it doesn't matter */
  183.     InsetRect(&template,1,0);
  184.     OffsetRect(&template,0,win->contR.bottom);
  185.     for (which = 0; which < HEAD_LIMIT; which++)
  186.     {
  187.         if ((teh=TENew(&template,&template))==nil)
  188.         {
  189.             WarnUser(MESS_TE,MemError());
  190.             goto failure;
  191.         }
  192.         (*messH)->txes[which] = teh;
  193.         (*teh)->txFont = FontID;
  194.         (*teh)->txSize = FontSize;
  195.         (*teh)->lineHeight = FontLead;
  196.         (*teh)->fontAscent = FontAscent;
  197.         (*teh)->clikLoop = MyClikLoop;
  198.         (*messH)->txRo[which] = (*tocH)->sums[sumNum].state==SENT;
  199.     }
  200.     (*messH)->txRo[ATTACH_HEAD-1] = True;
  201. #ifndef JENNY
  202.     (*messH)->txRo[FROM_HEAD-1] = True;
  203. #endif    
  204.     /*
  205.      * put in the text...
  206.      */
  207.     cp = LDRef(buffer);
  208.     cp[(*tocH)->sums[sumNum].length] = '\n';     /* a sentinel */
  209.     while (*cp++ != '\n');        /* skip sendmail from line */
  210.  
  211.     /*
  212.      * the headers
  213.      */
  214.     CycleBalls();
  215.     for (which=TO_HEAD; which < HEAD_LIMIT; which++)
  216.     {
  217.         teh = (*messH)->txes[which-1];
  218.         if (cp-*buffer >= (*tocH)->sums[sumNum].length) goto failure;
  219.         for (ep=cp; *ep!='\n'; ep++);
  220.         if (ep-*buffer >= (*tocH)->sums[sumNum].length) goto failure;
  221.         while (cp<ep && *cp++!=':');
  222.         if (*cp == ' ') cp++;
  223.  
  224.         if (cp<ep)
  225.             TESetText(cp,ep-cp,teh);
  226.         else
  227.             TESetText("",0,teh);
  228.         cp = ep+1;
  229.     }
  230.     
  231.     /*
  232.      * the body
  233.      */
  234.     CycleBalls();
  235.     ep+=2;    /* skip newline and header/body separator */
  236.     teh = (*messH)->txes[HEAD_LIMIT-1];
  237.     if (ep-*buffer < (*tocH)->sums[sumNum].length)
  238.     {
  239.         BlockMove(ep,*buffer,(*tocH)->sums[sumNum].length - (ep-*buffer));
  240.         SetHandleBig(buffer,(*tocH)->sums[sumNum].length - (ep-*buffer));
  241.         UL(buffer);
  242.         DisposHandle((*teh)->hText);
  243.         (*teh)->hText = buffer;
  244.         buffer = nil;
  245.         (*teh)->teLength = GetHandleSize((*teh)->hText);
  246.     }
  247.     else
  248.         TESetText("",0,teh);
  249.     (*messH)->txRo[ATTACH_HEAD-1] = 1;
  250.     if (buffer) ZapHandle(buffer);
  251.  
  252.     /*
  253.      * do precise sizing
  254.      */
  255.     MyWindowDidResize(win,&win->contR);
  256.  
  257.     return((*messH)->txes[TO_HEAD]);
  258.     
  259. failure:
  260.     if (buffer) DisposHandle(buffer);
  261.     for (which = 0; which < HEAD_LIMIT; which++)
  262.         if ((*messH)->txes[which-1])
  263.             TEDispose((*messH)->txes[which-1]);
  264.     return(nil);
  265.  
  266. }
  267.  
  268. /**********************************************************************
  269.  * MakeCompTitle - title a composition window
  270.  **********************************************************************/
  271. void MakeCompTitle(UPtr string, TOCType **tocH, int sumNum)
  272. {
  273.     Str255 scratch;
  274.  
  275.     *string = 0;
  276.     PCat(string,* (*tocH)->sums[sumNum].from ?
  277.                 (*tocH)->sums[sumNum].from : GetRString(scratch,NO_TO));
  278.     if (*(*tocH)->sums[sumNum].date)
  279.     {
  280.         PCat(string,"\p, ");
  281.         PCat(string,(*tocH)->sums[sumNum].date);
  282.     }
  283.     PCat(string,"\p, ");
  284.     PCat(string,* (*tocH)->sums[sumNum].subj ?
  285.              (*tocH)->sums[sumNum].subj : GetRString(scratch,NO_SUBJECT));
  286. }
  287.  
  288. /**********************************************************************
  289.  * FindCompTx - figure out which of the fields a given txe is.
  290.  **********************************************************************/
  291. int FindCompTx(MessType **messH, TEHandle txe)
  292. {
  293.     int tx;
  294.     
  295.     for (tx=0;tx<HEAD_LIMIT;tx++)
  296.         if ((*messH)->txes[tx] == txe)
  297.             return(tx);
  298.     
  299.     return (-1);
  300. }
  301.  
  302. /************************************************************************
  303.  * SaveComp - save a composition window
  304.  ************************************************************************/
  305. Boolean SaveComp(MyWindowPtr win)
  306. {
  307.     MessType **messH = (MessType **)((WindowPeek)win)->refCon;
  308.     TOCType **tocH = (*messH)->tocH;
  309.     long bytes = CountCompBytes(messH);
  310.     long offset;
  311.     int err;
  312.     
  313.      offset = FindTOCSpot(tocH,bytes);
  314.         
  315.     if ((err=BoxFOpen(tocH)) || (err = WriteComp(messH,(*tocH)->refN,offset)))
  316.     {
  317.         FileSystemError(WRITE_MBOX,(*tocH)->name,err);
  318.         return(False);
  319.     }
  320.         
  321.     (*tocH)->sums[(*messH)->sumNum].offset = offset;
  322.     (*tocH)->sums[(*messH)->sumNum].length = bytes;
  323.     (*tocH)->sums[(*messH)->sumNum].flags &= ~FLAG_NBK;
  324.     if ((*tocH)->refN) (void) SetEOF((*tocH)->refN,offset+bytes);
  325.     UpdateSum(messH, offset, bytes);
  326.     (*tocH)->dirty = True;
  327.     win->isDirty = False;
  328.     return(True);
  329. }
  330.     
  331. /************************************************************************
  332.  * CountCompBytes - count up the bytes in a message under composition
  333.  ************************************************************************/
  334. long CountCompBytes(MessType **messH)
  335. {
  336.     int which;
  337.     long bytes = 0;
  338.     Str255 scratch;
  339.     TEHandle teh;
  340.     int thisOne;
  341.     
  342.     /*
  343.      * headers
  344.      */
  345.     for (which=0;which<HEAD_LIMIT-1;which++)
  346.     {
  347.         teh = (*messH)->txes[which];
  348.         thisOne = (*teh)->teLength;
  349.         if ((*(*teh)->hText)[thisOne-1] != '\n') thisOne++;
  350.         bytes += thisOne;
  351.         GetRString(scratch,HEADER_STRN+which+1);
  352.         bytes += *scratch + 1;
  353.     }
  354.     
  355.     /*
  356.      * body
  357.      */
  358.     teh = (*messH)->txes[HEAD_LIMIT-1];
  359.     thisOne = (*teh)->teLength;
  360.     if ((*(*teh)->hText)[thisOne-1] != '\n') thisOne++;
  361.     bytes += thisOne;
  362.     
  363.     bytes += 1; /* a blank line */
  364.  
  365.     SumToFrom(nil,scratch);
  366.     bytes += strlen(scratch);
  367.     return (bytes);
  368. }
  369.  
  370. /************************************************************************
  371.  * WriteComp - write a comp message to a particular spot in a particular
  372.  * file.
  373.  ************************************************************************/
  374. int WriteComp(MessType **messH, short refN, long offset)
  375. {
  376.     int which;
  377.     long count;
  378.     UHandle text;
  379.     int err;
  380.     Str255 fromLine;
  381.     long spot;
  382.     
  383.     /*
  384.      * sendmail-style From line
  385.      */
  386.     CycleBalls();
  387.     SetFPos(refN, fsFromStart, offset);
  388.     SumToFrom(nil,fromLine);
  389.     count = strlen(fromLine);
  390.     if (err=FSWrite(refN,&count,fromLine)) return(err);
  391.     
  392.     /*
  393.      * headers
  394.      */
  395.     for (which=0;which<HEAD_LIMIT-1;which++)
  396.         if (err = WriteCompHeader(refN,messH,which)) return(err);
  397.  
  398.     /*
  399.      * blank line
  400.      */
  401.     count = 1;
  402.     if (err = FSWrite(refN,&count,"\n")) return(err);
  403.     
  404.     /*
  405.      * body
  406.      */
  407.     GetFPos(refN,&spot);
  408.     (*(*messH)->tocH)->sums[(*messH)->sumNum].bodyOffset = spot-offset;
  409.     (*(*messH)->tocH)->dirty = True;
  410.     CycleBalls();
  411.     text = (*(*messH)->txes[HEAD_LIMIT-1])->hText;
  412.     count = (*(*messH)->txes[HEAD_LIMIT-1])->teLength;
  413.     LDRef(text);
  414.     err = FSWrite(refN,&count,*text);
  415.     UL(text);
  416.     if (err) return(err);
  417.     if ((*text)[count-1] != '\n')
  418.     {
  419.         count = 1;
  420.         err = FSWrite(refN,&count,"\n");
  421.     }
  422.     return(err);
  423. }
  424.  
  425. /************************************************************************
  426.  * UpdateSum - stick values from comp message into sum
  427.  ************************************************************************/
  428. void UpdateSum(MessType **messH, long offset, long length)
  429. {
  430.     TOCType **tocH = (*messH)->tocH;
  431.     int sumNum = (*messH)->sumNum;
  432.     MSumType *sum = (*tocH)->sums + sumNum;
  433.  
  434.     LDRef(tocH);
  435.     SuckHeaderText(sum->from,sizeof(sum->from),(*messH)->txes[TO_HEAD-1]);
  436.     if (!*sum->from)
  437.         SuckHeaderText(sum->from,sizeof(sum->from),(*messH)->txes[BCC_HEAD-1]); 
  438.     SuckHeaderText(sum->subj,sizeof(sum->subj),(*messH)->txes[SUBJ_HEAD-1]);
  439.     sum->offset = offset;
  440.     sum->length = length;
  441.     if (*sum->from)
  442.     {
  443.         if (sum->state==UNSENDABLE) SetState(tocH,sumNum,SENDABLE);
  444.     }
  445.     else if (sum->state != UNSENDABLE)
  446.     {
  447.         SetState(tocH,sumNum,UNSENDABLE);
  448.     }
  449.     BeautifySum(sum);
  450.     /* calculate fromTrunc */
  451.     
  452.     /*
  453.      * retitle window
  454.      */
  455.     if ((*messH)->win)
  456.     {
  457.         Str255 scratch;
  458.         MakeCompTitle(scratch,tocH,(*messH)->sumNum);
  459.         SetWTitle((*messH)->win,scratch);
  460.     }
  461.     
  462.     /*
  463.      * finally, invalidate the line in the toc
  464.      */
  465.     CalcSumLengths(tocH,(*messH)->sumNum);
  466.     InvalSum(tocH,(*messH)->sumNum);
  467.     UL(tocH); 
  468. }
  469.  
  470. /************************************************************************
  471.  * WriteCompHeader - write a particular header to a file
  472.  ************************************************************************/
  473. int WriteCompHeader(short refN,MessType **messH,int which)
  474. {
  475.     char *bp, *ep;
  476.     register char *cp;
  477.     UHandle text;
  478.     Boolean anyTabs = False;
  479.     Str255 name;
  480.     int err;
  481.     long count;
  482.     
  483.     /*
  484.      * write out the name of the header
  485.      */
  486.     GetRString(name,HEADER_STRN+which+1);
  487.     PCatC(name,' ');
  488.     count = *name;
  489.     if (err=FSWrite(refN,&count,name+1)) return(err);
  490.     
  491.     /*
  492.      * set up for the header text
  493.      */
  494.     text = (*(*messH)->txes[which])->hText;
  495.     bp = LDRef(text);
  496.     ep = bp + (*(*messH)->txes[which])->teLength;
  497.     
  498.     /*
  499.      * walk through text, replacing \n with \t
  500.      */
  501.     for (cp=bp; cp<ep-1; cp++) if (*cp == '\n') {*cp = '\t'; anyTabs=True;};
  502.     
  503.     /*
  504.      * write it out
  505.      */
  506.     count = ep-bp;
  507.     err = FSWrite(refN,&count,bp);
  508.     if (!err && (!count || *cp!='\n'))
  509.     {
  510.         count = 1;
  511.         err = FSWrite(refN,&count,"\n");
  512.     }
  513.     
  514.     /*
  515.      * replace the \t's with \n's
  516.      */
  517.     if (anyTabs) for (cp=bp; cp<ep; cp++) if (*cp == '\t') *cp = '\n';
  518.     
  519.     UL(text);
  520.     return(err);
  521. }
  522.  
  523. /************************************************************************
  524.  * SuckHeaderText - get the text of a header for insertion into a summary
  525.  ************************************************************************/
  526. void SuckHeaderText(UPtr string,int size,TEHandle teh)
  527. {
  528.     register char *cp;
  529.     int bytes = (*teh)->teLength;
  530.     
  531.     /*
  532.      * grab the text
  533.      */
  534.     if (bytes>size-2) bytes = size-2;
  535.     strncpy(string+1,*(*teh)->hText,bytes);
  536.     string[bytes+1] = 0;
  537.     string[0] = bytes;
  538.     
  539.     /*
  540.      * change newlines to spaces
  541.      */
  542.     for (cp=string+1;*cp;cp++) if (*cp=='\n') *cp = ' ';
  543.     
  544.     TrimWhite(string);
  545. }
  546.  
  547. /**********************************************************************
  548.  * QueueSelectedMessages - queue all selected messages
  549.  **********************************************************************/
  550. int QueueSelectedMessages(TOCType **tocH,short toState,uLong when)
  551. {
  552.     int sumNum;
  553.     int err = 0;
  554.     long zs = ZoneSecs();
  555.     
  556.     for (sumNum = 0; sumNum < (*tocH)->count; sumNum++)
  557.     {
  558.         if ((*tocH)->sums[sumNum].selected)
  559.         {
  560.         TimeStamp(tocH,sumNum,when,zs);
  561.             if (toState==QUEUED)
  562.             {
  563.                 if (*(*tocH)->sums[sumNum].from)
  564.                 {
  565.                     if ((*tocH)->sums[sumNum].state!=SENT) SetState(tocH,sumNum,QUEUED);
  566.                 }
  567.                 else
  568.                     err = 1;
  569.             }
  570.             else if ((*tocH)->sums[sumNum].state!=SENT)
  571.             {
  572.                 SetState(tocH,sumNum,*(*tocH)->sums[sumNum].from? SENDABLE:UNSENDABLE);
  573.             }
  574.         }
  575.     }
  576. done:
  577.     if (err)
  578.         DoNumBigAlert(Stop,CANT_QUEUE);
  579.     SetSendQueue();
  580.     return(err);
  581. }
  582. /************************************************************************
  583.  * CreateMessageBody - put a blank message body into a buffer
  584.  ************************************************************************/
  585. void CreateMessageBody(UPtr buffer)
  586. {
  587.     Str255 s;
  588.     char *ep;
  589.     
  590.     ep = buffer;
  591.     
  592.     /*
  593.      * from line
  594.      */
  595.     strcpy(ep,"From "); ep+= 5;
  596.     GetReturnAddr(s,False);strncpy(ep,s+1,*s);ep += *s;*ep++ = ' ';
  597.     LocalDateTimeStr(ep); p2cstr(ep);
  598.     ep += strlen(ep);
  599.     
  600.     /*
  601.      * headers
  602.      */
  603.     GetRString(s,HEADER_STRN+TO_HEAD);strncpy(ep,s+1,*s);ep+= *s;*ep++ ='\n';
  604.     GetRString(s,HEADER_STRN+FROM_HEAD);strncpy(ep,s+1,*s);ep+= *s;*ep++ =' ';
  605.     GetReturnAddr(s,True);strncpy(ep,s+1,*s);ep+= *s;*ep++ ='\n';
  606.     GetRString(s,HEADER_STRN+CC_HEAD);strncpy(ep,s+1,*s);ep+= *s;*ep++ ='\n';
  607.     GetRString(s,HEADER_STRN+BCC_HEAD);strncpy(ep,s+1,*s);ep+= *s;*ep++ ='\n';
  608.         
  609.     /*
  610.      * blank line and "body"
  611.      */
  612.     strcpy(ep,"\n\n");    
  613.